package edu.serg.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.OutputStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.TransformerFactory;

import javax.xml.transform.*;


import org.apache.xml.dtm.ref.DTMNodeList;
import org.apache.log4j.Logger;
import org.apache.xpath.NodeSet;
import org.apache.xpath.NodeSetDTM;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.apache.xml.dtm.DTMIterator;

import edu.serg.mbar.ucon.AuthenticationManager;
import edu.serg.mbar.ucon.meta.MBARNamespaceContext;

public class XMLUtils {
	static Logger log = Logger.getLogger(XMLUtils.class);

//	public String XmlToString(Node nl) {
//		TransformerFactory tFactory = TransformerFactory.newInstance();
//		Transformer transformer = null;
//		StringWriter sw = null;
//		try {
//			transformer = tFactory.newTransformer();
//
//			DOMSource source = new DOMSource(nl);
//			sw = new StringWriter();
//			StreamResult result = new StreamResult(sw);
//			transformer.transform(source, result);
//
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			log.info(e.getMessage());
//			e.printStackTrace();
//		}
//		if (sw != null) {
//			return sw.toString();
//		} else
//			return "<<Error converting XML>>";
//	}
	public String getStringValueOfNode(Node node) {
		try {
			/*
			 * Alternate method for automatic extraction:
			 * 
			 * PrefixResolver resolver = new PrefixResolverDefault(doc
			 * .getDocumentElement());
			 * path.getXPathContext().setNamespaceContext(resolver);
			 */

			XPathFactory xpf = XPathFactory.newInstance();
			XPath path = xpf.newXPath();
			path.setNamespaceContext(new MBARNamespaceContext());
String value =			path.evaluate("./text()", node);
return value.trim();
		} catch (Exception e) {
			e.printStackTrace();
			log.debug(e.getMessage());
			return "<<Error getting the ./text() or string value of Node >>";
		}
	}

	public String xPathEvaluateToString(Document doc, String xpath) {
		try {
			/*
			 * Alternate method for automatic extraction:
			 * 
			 * PrefixResolver resolver = new PrefixResolverDefault(doc
			 * .getDocumentElement());
			 * path.getXPathContext().setNamespaceContext(resolver);
			 */

			XPathFactory xpf = XPathFactory.newInstance();
			XPath path = xpf.newXPath();
			path.setNamespaceContext(new MBARNamespaceContext());

			return path.evaluate(xpath, doc);
		} catch (Exception e) {
			e.printStackTrace();
			log.debug(e.getMessage());
			return "<<Error evaluating xpath expression: " + xpath + " >>";
		}
	}

	public Node xPathEvaluateToNode(Node node, String xpath) {
		try {
			
			XPathFactory xpf = XPathFactory.newInstance();
			XPath path = xpf.newXPath();
			path.setNamespaceContext(new MBARNamespaceContext());

			Node retrievedNode = (Node) path.evaluate(xpath, node, XPathConstants.NODE);

			return retrievedNode;
		} catch (Exception e) {
			e.printStackTrace();
			log.debug(e.getMessage());
			log.debug("<<Error evaluating xpath expression: " + xpath + " >>");
			return null;
		}
	}

//	public NodeSet xPathEvaluateToNodeSet(Document doc, String xpath) {
//		try {
//			
//			XPathFactory xpf = XPathFactory.newInstance();
//			XPath path = xpf.newXPath();
//			path.setNamespaceContext(new MBARNamespaceContext());
//
//			NodeSet nodeset = (NodeSet) path.evaluate(xpath, doc,
//					XPathConstants.NODESET);
//
//			return nodeset;
//		} catch (Exception e) {
//			e.printStackTrace();
//			log.debug(e.getMessage());
//			log.debug("<<Error evaluating xpath expression: " + xpath + " >>");
//			return null;
//		}
//	}


	public NodeList xPathEvaluateToNodeList(Node node, String xpath) {
		try {
//			log.debug("Recieved a request to parse XPath='"+ xpath);
			XPathFactory xpf = XPathFactory.newInstance();
			XPath path = xpf.newXPath();
			path.setNamespaceContext(new MBARNamespaceContext());
			
//			NodeSet nodeSet= new NodeSet();
			NodeList nodeList= (NodeList)  path.evaluate(xpath, node,
					XPathConstants.NODESET);
						
//			nodeSet= (NodeSet) nodeList;
			
			return nodeList;
			
		} catch (Exception e) {
			e.printStackTrace();
			log.debug("<<Error evaluating xpath expression: " + xpath + " >>");
			log.debug(e.getMessage());
			return null;
		}
	}

	
	
	public Document parseXmlFromFile(String filename) throws SAXException,
			IOException, ParserConfigurationException {
		InputSource in = new InputSource(new FileInputStream(filename));
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setNamespaceAware(true);

		DocumentBuilder db = dbf.newDocumentBuilder();

		Document doc;
		doc = db.parse(in);
		return doc;
	}
	
	
	/**
	 * This Function parses the XML from string
	 * @param xmlString
	 * 		The xml in the form of String
	 * @return
	 * 		Returns a document
	 * @throws SAXException
	 * @throws IOException
	 * @throws ParserConfigurationException
	 */
	public Document parseXmlFromString(String xmlString) throws SAXException,
		IOException, ParserConfigurationException {
		InputSource in = new InputSource();
		in.setCharacterStream(new StringReader(xmlString));
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setNamespaceAware(true);

		DocumentBuilder db = dbf.newDocumentBuilder();

		Document doc;
		doc = db.parse(in);
		return doc;
}
	
	
	public String xmlFromNodetoString(Node node){
//		log.debug("----------------Xml From Node '"+ node.getNodeName()+"'----------------");
		String xmlRepresentation ="";
		
		TransformerFactory tFactory = TransformerFactory.newInstance();

		try {
//		    tFactory.setAttribute("indent-number", new Integer(4));
	
		  Transformer transformer = tFactory.newTransformer();
		  transformer.setOutputProperty(OutputKeys.METHOD, "xml");

		  // Set to "no" if you don't want indented output
		  transformer.setOutputProperty(OutputKeys.INDENT, "yes");

		  // Some versions of Xalan require the following instead of
		  // the "indent-number" attribute above
		  transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

		  DOMSource source = new DOMSource(node);

		  // Output to string - could also output to File, socket, etc.
		  StringWriter sw = new StringWriter();
		  StreamResult result = new StreamResult(sw);
		  transformer.transform(source, result);

		  xmlRepresentation= sw.toString();
//		  log.debug(xmlRepresentation);

		  } catch (Exception ex) { log.error(ex.getMessage());}
		  
//	 	}


	 	return xmlRepresentation;

	}
	
//	private NodeSet DTMNodeListToNodeSetConverter(DTMNodeList nodeList){
//			NodeSet nodeSet = new NodeSet();
//			for (int i=0; i<nodeList.getLength();i++){
//				
//			}
//			return nodeSet;
//	}
}

